package com.kanshu.basictest;

import android.app.Activity;
import android.app.Application;
import android.content.ComponentCallbacks;
import android.content.ComponentCallbacks2;
import android.content.res.Configuration;

import com.kanshu.basictest.sys.CrashHandler;

import java.util.ArrayList;
import java.util.List;

/**
 * Application类：
 * <p>
 * 介绍:
 * 1.Application类时用于维护全局应用程序状态的基类。
 * 2.我们可以为应用提供自己的Application实现：
 * >>>a.创建Application的子类；
 * >>>b.将子类的全限定名称提供到AndroidManifest.xml文件<application>标签中的“android：name”属性。
 * 3. 在创建应用程序/包的进程时，Application类或Application类的子类在任何其他类之前实例化。
 * <p>
 * 从Applicaiton类的方法可以看出，Applicaiton类的应用场景有：（已按优先级排序）
 * 1.初始化 应用程序级别 的资源，如全局对象、环境配置变量等
 * 2.数据共享、数据缓存，如设置全局共享变量、方法等
 * 3.获取应用程序当前的内存使用情况，及时释放资源，从而避免被系统杀死
 * 4.监听 应用程序 配置信息的改变，如屏幕旋转等
 * 5.监听应用程序内 所有Activity的生命周期
 */
public class MyApp extends Application {

    public static MyApp sInstance;

    private static final List<Activity> ACTIVITIES = new ArrayList<>();

    /**
     * onCreate()方法：
     * 介绍:
     * >>>1.在应用程序启动时调用, 任何Activity、Service和 receiver的创建不会在这之前调用，除了Content Provider。
     * >>>2.该方法默认的实现为空。重写该方法时，不再这里面执行耗时操作，实现越快越好。因为这关系到应用的启动速度。
     * 作用：
     * >>>初始化 应用程序级别 的资源，如全局对象、环境配置变量、图片资源初始化、推送服务的注册等
     */
    @Override
    public void onCreate() {
        super.onCreate();
        sInstance = this;
        CrashHandler crashHandler = CrashHandler.getInstance();
        crashHandler.init(this);
    }


    /**
     * onConfigurationChanged()方法：
     * <p>
     * 介绍:
     * >>>1.此方法来自于{@link ComponentCallbacks}接口
     * >>>2.当组件运行时，设备配置发生变化时由系统调用。
     * >>>3.请注意，与activity不同，其他组件在配置更改时永远不会重新启动：它们必须始终处理更改的结果，例如通过重新检索资源。
     * >>>4.更多的信息可以查看<a href="https://developer.android.google.cn/guide/topics/resources/runtime-changes">处理运行时变更</a>
     *
     * @param newConfig 新的设备配置
     */
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
    }


    /**
     * onLowMemory()方法：
     * <p>
     * 介绍:
     * >>>1.此方法来自于{@link ComponentCallbacks}接口
     * >>>2.当整个系统内存不足时调用此方法，并且主动运行的进程应调整（减少）其内存使用量。
     * >>>3.虽然没有定义调用它的确切点，但通常会在所有后台进程都被杀死时发生。 也就是说，在达到杀死进程托管服务和前台UI之前，我们希望避免被杀死。
     * 用途:
     * 1.可以重写该方法来释放缓存或其它不必要的资源，此方法返回之后，系统将进行垃圾回收操作。
     * <p>
     * 注意:
     * 当然,最好的方式是，
     * 在API>=14时，从ComponentCallbacks2实现ComponentCallbacks2.onTrimMemory（int），以根据各种级别的内存需求逐步卸载资源。
     * 在API<14时，重写onLowMemory()方法实现内存释放。
     * 另外，{@link ComponentCallbacks2#TRIM_MEMORY_COMPLETE}的级别和onLowMemory()一致。
     */
    @Override
    public void onLowMemory() {
        super.onLowMemory();
    }

    /**
     * onTrimMemory()方法：
     * <p>
     * 介绍:
     * >>>1.此方法来自于{@link ComponentCallbacks2}接口
     * >>>2.ComponentCallbacks2接口对ComponentCallbacks接口进行了扩展，增加了新的回调方法--onTrimMemory(int)，以用于更加精细的内存管理。
     * >>>3.当操作系统认为当前是一个释放进程所占用不必要的内存好时机时，会调用此方法。
     * <p>
     * <p>
     * 用途:
     * 1.可以重写该方法来释放缓存或其它不必要的资源，此方法返回之后，系统将进行垃圾回收操作。
     * 2. 如果您不根据此回调定义的内存级别来减少资源，系统更有可能在最近最少使用（LRU）列表中缓存进程时杀死您的进程，从而导致需要重新启动应用程序 并在用户返回时恢复所有状态。
     * <p>
     * 注意： 该回调方法中提供的各内存级别之间不存在线性递进关系，而仅仅是对于内存可用性的不同种类的表示。
     * <p>
     * <p>
     * 内存级别：
     * ---app正在前台运行时：
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_RUNNING_MODERATE}：设备即将进入低内存运行状态，app正在运行，并且不能被杀死。
     * API:16
     * 内存不足级别：5
     * 处理：设备的运行内存偏低， 您的运行进程可能希望释放一些不需要的资源以供其他地方使用。
     * <p>
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_RUNNING_LOW}：设备的运行内存非常低，app正在运行，并且不能被杀死。
     * API:16
     * 内存不足级别：10
     * 处理：设备的运行内存非常低， 此时需要尽可能释放一些不必要的资源以提升系统性能。
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_RUNNING_CRITICAL}：设备的运行内存极低，app正在运行，尚未被视为一个可以杀死的进程。
     * API:16
     * 内存不足级别：15
     * 处理:如果应用程序还没有释放资源，那么系统将开始杀死后台进程以上空间。此时需要立即释放非关键的资源来方式设备性能下降。
     * <p>
     * ---app的UI不可见时：
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_UI_HIDDEN}：app的UI不再可见。
     * API:14
     * 内存不足级别：20
     * 处理：这是一个释放大量的仅被UI占用的资源的好时机。
     * <p>
     * ---当app进程进入到后台的LRU（最近最少使用）列表时：
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_BACKGROUND}：系统内存不足，您的进程接近LRU列表的开头。
     * API:14
     * 内存不足级别：40
     * 处理：虽然应用程序进程没有太大的可能被杀死，但系统可能已经杀死了LRU列表中的其它进程，因此您应该释放易于恢复的资源，这样您的进程将保留在列表中并在用户快速恢复时 返回您的应用。
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_MODERATE}：系统内存不足，您的进程接近LRU列表的中间位置。
     * API:14
     * 内存不足级别：60
     * 处理:系统进一步受限于内存，你的进程有可能被杀死。
     * >>>{@link ComponentCallbacks2#TRIM_MEMORY_COMPLETE}：系统内存不足，如果系统现在没有恢复内存，那么您的进程是第一个被杀死的进程之一。
     * API:14
     * 内存不足级别：80
     * 处理：您应该绝对释放对恢复应用状态不重要的所有内容。
     * <p>
     * 注意：
     * 当系统开始杀死LRU列表中的进程时，虽然它主要是自下而上的，但它确实考虑了哪些进程占用了更多内存，
     * 如果杀死这些进程将会释放更多的内存。 因此，在整体LRU列表中消耗的内存越少，
     * 保留在列表中并且能够快速恢复的机会就越大
     */
    @Override
    public void onTrimMemory(int level) {
        super.onTrimMemory(level);
    }


    /**
     * onTerminate()方法：
     * 调用时刻：应用程序结束时调用
     * 但该方法只用于Android仿真机测试，在Android产品机是不会调用的
     */
    @Override
    public void onTerminate() {
        super.onTerminate();
    }

    @Override
    public void registerActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        super.registerActivityLifecycleCallbacks(callback);
    }

    @Override
    public void unregisterActivityLifecycleCallbacks(ActivityLifecycleCallbacks callback) {
        super.unregisterActivityLifecycleCallbacks(callback);
    }

    @Override
    public void registerComponentCallbacks(ComponentCallbacks callback) {
        super.registerComponentCallbacks(callback);
    }

    @Override
    public void unregisterComponentCallbacks(ComponentCallbacks callback) {
        super.unregisterComponentCallbacks(callback);
    }


    @Override
    public void registerOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
        super.registerOnProvideAssistDataListener(callback);
    }

    @Override
    public void unregisterOnProvideAssistDataListener(OnProvideAssistDataListener callback) {
        super.unregisterOnProvideAssistDataListener(callback);
    }


    public static void addActivity(Activity activity) {
        if (!ACTIVITIES.contains(activity)) {
            ACTIVITIES.add(activity);
        }
    }

    public static void removeActivity(Activity activity) {
        if (ACTIVITIES.contains(activity)) {
            ACTIVITIES.remove(activity);
        }
    }

    public static void closeAllActivity() {
        for (Activity activity : ACTIVITIES) {
            activity.finish();
        }
    }

}
